/*

Stickman Adventure - a game created by Daco & his cousin

Copyright (C) 2011-2012  DacoTaco & Wouterke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


*/
#include "Object_collection.h"
	
char Compare_Map[TYPE_LIST_SIZE][TYPE_LIST_SIZE-1]={
		{INVALID,INVALID,INVALID,INVALID}, //BG
		{INVALID,INVALID,INVALID,INVALID}, //PLATFORM
		{OBJECT_PLATFORM,OBJECT_ENEMY,OBJECT_PLAYER,INVALID}, //ENEMY
		{OBJECT_PLATFORM,OBJECT_ENEMY,INVALID,INVALID}, //PLAYER
		{OBJECT_BACKGROUND,OBJECT_PLATFORM,OBJECT_ENEMY,OBJECT_PLAYER} //SCREEN
};
//hacky fix
#ifdef DEBUG
	#define gprintf printf
#else
	#define gprintf(...)
#endif

_Object_collection Collector;

_Object_collection::_Object_collection(void)
{
	for(unsigned char type1 = 0; type1 < TYPE_LIST_SIZE; type1++)	
	{
		_Objects[type1].clear();
	}
	return;
}
_Object_collection::~_Object_collection(void)
{
	for(int x = 0;x < TYPE_LIST_SIZE;x++)
	{
		if(_Objects[x].size() <= 0)
			continue;
		for(unsigned int z = 0;z < _Objects[x].size();z++)
		{
			if(_Objects[x].at(z) != NULL)
			{
				if(_Objects[x].at(z) == NULL)
					return;
				delete _Objects[x].at(z);
				//no need to null the pointer in the vector cause we are going to delete the entry anyway
				DeleteIndex(x,z);
			}
		}
		_Objects[x].clear();
	}
	return;
}

char _Object_collection::AddObject(Object* _object)
{
	if(_object == NULL)
		return 0;
	_Objects[_object->getType()].push_back(_object);
	return 1;
}


char _Object_collection::DeleteIndex(char type, char index)
{
	if(index == 0 || (unsigned)index > _Objects[type].size())
		return 0;
	_Objects[type].erase(_Objects[type].begin()+(index-1));
	return 1;
}

int _Object_collection::GetSize(int object_type)
{
	return _Objects[object_type].size();
}
Object* _Object_collection::getObject(int object_type , unsigned int index)
{
	if(_Objects[object_type].size() > 0 && index <= _Objects[object_type].size() )
		return _Objects[object_type].at(index);
	return NULL;
}
Object* _Object_collection::GetPlayer(int Player_nr)
{
	if(Player_nr < 1 || Player_nr > GetSize(OBJECT_PLAYER) )
		return NULL;
	return getObject(OBJECT_PLAYER,Player_nr-1);

}
int _Object_collection::Check_Collision(Object* o,char type,int velocity,int* y_ground , int* x_wall)
{
	if(type >= TYPE_LIST_SIZE || _Objects[type].size() < 1)
		return 0;

	char col = 0;
	char ret = 0;
	
	//A = object, B = player
	//The sides of the rectangles 
	int leftA, leftB; 
	int rightA, rightB; 
	int topA, topB; 
	int bottomA, bottomB; 
	//Calculate the sides of rect A 
	if(o->GetColRect() == NULL)
		return 0;
	leftA = o->GetColRect()->x; 
	rightA = o->GetColRect()->x + o->GetColRect()->w; 
	topA = o->GetColRect()->y; 
	bottomA = o->GetColRect()->y +o->GetColRect()->h; 

	for(unsigned int x = 0;x < _Objects[type].size();x++)
	{
		Object* temp=getObject(type,x);
		//Calculate the sides of rect B
		if(temp->GetColRect() == NULL)
			continue;
		leftB =temp->GetColRect()->x; 
		rightB = temp->GetColRect()->x +temp->GetColRect()->w; 
		topB = temp->GetColRect()->y; 
		bottomB = temp->GetColRect()->y + temp->GetColRect()->h;


		if(
			type==OBJECT_PLATFORM &&
			y_ground != NULL && 
			leftA < rightB && rightA > leftB &&
			( topB >= bottomA || bottomA <= bottomB ) &&
			topB < *y_ground
			)
		{
			*y_ground = topB;
		}
		if ( type==OBJECT_PLATFORM && 
			 velocity != 0 && 
			 x_wall != NULL && 
			 ( topB <= bottomA && bottomB >= topA) )
		{
			if(velocity > 0 &&
				leftB < *x_wall && rightA <= leftB)
			{
				*x_wall = leftB;
			}
			else if(velocity < 0 &&
				rightB > *x_wall && leftA >= rightB )
			{
				*x_wall = rightB;
			}
		}


		//If any of the sides from A are outside of B 
		if( topA >= (bottomB - 16) && topA <= bottomB && topA >= topB && leftA <= rightB && rightA >= leftB )
		{
			//above us
			ret |= 16;
		}
		if( bottomA >= topB && bottomA <= bottomB && leftA < rightB && rightA > leftB )
		{
			//something is underneeth us.
			ret |= 8;
		}
		if( rightA >= leftB && leftA < rightB && bottomA > topB && topA < bottomB )
		{ 
			//R------->L
			//the Right side of A touches the left of B
			ret |= 4; 
		} 
		if( leftA <= rightB && rightA > leftB && bottomA > topB && topA < bottomB )
		{ 
			//L<------R
			//the left side of A touches the right of B
			ret |= 2; 
		}
		//If none of the sides from A are outside B 
		if(ret!=0){
			o->CollisionAction(temp,ret); 
			//temp->CollisionAction(o);
			col |= ret;
			ret=0;
		}
	}
	//gprintf("ret of col = %d (%d & %d)(%d & %d)\n",ret,bottomA,topB,rightA ,leftB);
	return col;
}

void _Object_collection::UpdateObjects()
{
	int y_ground, x_wall;
	char collision;
	for(unsigned char type1 = 0; type1 < TYPE_LIST_SIZE; type1++)	
	{
		for(unsigned char x = 0; x < _Objects[type1].size(); x++)
		{
			if(getObject(type1,x) == NULL)
				continue;
			collision = 0;
			y_ground = 0xFFFFFF; // of = 0 for up
			if(getObject(type1,x)->GetVelocity() > 0)
				x_wall = 0xFFFFFF; // or = 0 for left
			else
				x_wall = 0;
			
			//collision check enkel met de nodige types
			
			for(unsigned char typeIndex=0 ; typeIndex < TYPE_LIST_SIZE-1 ; typeIndex++){
							//Check_Collision(Object* o,         char type,                    int velocity,                     int* y_ground , int* x_wall)
				collision |=  Check_Collision(getObject(type1,x),Compare_Map[type1][typeIndex],getObject(type1,x)->GetVelocity(),&y_ground,&x_wall);
				//printf("%i;%i=%i \n",type1,typeIndex,Compare_Map[type1][typeIndex]);
			}
			getObject(type1,x)->Update(collision,y_ground,x_wall);
			//getObject(OBJECT_SCREEN,0)->Update(0,0,0);
		}
	}
}